import { defineStore } from 'pinia';
import { getCurrentInstance, nextTick, onBeforeUnmount, reactive, type UnwrapNestedRefs } from 'vue';

interface ListOption {
  label: string;
  value: string;
}

interface State {
  list1: ListOption[];
  list2: ListOption[];
  list3: ListOption[];
}

type Listener = (state: UnwrapNestedRefs<State>) => void;

enum LoadStatus {
  PRE_LOAD,
  LOADING,
  POST_LOAD,
}

function getList() {
  return Promise.resolve<ListOption[]>([]);
}

export const useListStore = defineStore('list', () => {
  const state = reactive<State>({
    list1: [],
    list2: [],
    list3: [],
  });

  function loadList1() {
    return getList().then((list) => (state.list1 = list));
  }

  function loadList2() {
    return getList().then((list) => (state.list2 = list));
  }

  function loadList3() {
    return getList().then((list) => (state.list3 = list));
  }

  let _load = LoadStatus.PRE_LOAD;
  const _listener: Listener[] = [];

  function tryOnInitialized(listener: Listener, sync = true) {
    if (_load === LoadStatus.POST_LOAD) {
      // 异步的作用是不用考虑 tryOnInitialized 函数执行的位置，不会卡“暂时性死区”的 bug
      sync ? listener(state) : nextTick(() => listener(state));
    } else if (!_listener.includes(listener)) {
      _listener.push(listener);

      // 要考虑极限边界情况（组件已销毁，但数据仍未加载完毕）
      if (getCurrentInstance()) {
        onBeforeUnmount(() => {
          for (let i = _listener.length; i--; ) {
            if (_listener[i] === listener) {
              _listener.splice(i, 1);
              break;
            }
          }
        });
      }
    }
  }

  function initialize(reload = false) {
    // 需要重载且属于加载中 || 不需要重载且不属于未加载
    if ((reload && _load === LoadStatus.LOADING) || (!reload && _load !== LoadStatus.PRE_LOAD)) return;

    _load = LoadStatus.LOADING;

    Promise.allSettled([loadList1(), loadList2(), loadList3()]).finally(() => {
      _load = LoadStatus.POST_LOAD;

      while (_listener.length) {
        _listener.shift()!(state);
      }
    });
  }

  initialize();

  return { state, initialize, tryOnInitialized };
});

// 使用
const { state, tryOnInitialized } = useListStore();
tryOnInitialized(() => {
  // ...
});
